import { createSlice, createAsyncThunk, PayloadAction } from '@reduxjs/toolkit'
import { Plugin, PluginVersion, PluginStats, PluginFilters, PluginPaginatedResponse } from '@/types/api'
import { pluginService } from '@/services/api/pluginService'

interface PluginState {
  // Marketplace
  plugins: Plugin[]
  currentPlugin: Plugin | null
  pluginVersions: PluginVersion[]
  pluginStats: PluginStats | null
  
  // Developer plugins
  myPlugins: Plugin[]
  
  // UI state
  isLoading: boolean
  isLoadingVersions: boolean
  isLoadingStats: boolean
  error: string | null
  
  // Pagination
  pagination: {
    page: number
    limit: number
    total: number
    totalPages: number
    hasNext: boolean
    hasPrev: boolean
  } | null
  
  // Filters
  filters: PluginFilters
}

const initialState: PluginState = {
  plugins: [],
  currentPlugin: null,
  pluginVersions: [],
  pluginStats: null,
  myPlugins: [],
  isLoading: false,
  isLoadingVersions: false,
  isLoadingStats: false,
  error: null,
  pagination: null,
  filters: {
    page: 1,
    limit: 20,
    search: '',
    sortBy: 'createdAt',
    sortOrder: 'desc',
  },
}

// Async thunks
export const fetchPlugins = createAsyncThunk(
  'plugins/fetchPlugins',
  async (filters: PluginFilters, { rejectWithValue }) => {
    try {
      const response = await pluginService.getPlugins(filters)
      return response.data
    } catch (error: any) {
      return rejectWithValue(error.response?.data?.error?.message || 'Failed to fetch plugins')
    }
  }
)

export const fetchPluginById = createAsyncThunk(
  'plugins/fetchPluginById',
  async (id: string, { rejectWithValue }) => {
    try {
      const response = await pluginService.getPluginById(id)
      return response.data
    } catch (error: any) {
      return rejectWithValue(error.response?.data?.error?.message || 'Failed to fetch plugin')
    }
  }
)

export const fetchPluginVersions = createAsyncThunk(
  'plugins/fetchPluginVersions',
  async (pluginId: string, { rejectWithValue }) => {
    try {
      const response = await pluginService.getPluginVersions(pluginId)
      return response.data
    } catch (error: any) {
      return rejectWithValue(error.response?.data?.error?.message || 'Failed to fetch versions')
    }
  }
)

export const fetchPluginStats = createAsyncThunk(
  'plugins/fetchPluginStats',
  async (pluginId: string, { rejectWithValue }) => {
    try {
      const response = await pluginService.getPluginStats(pluginId)
      return response.data
    } catch (error: any) {
      return rejectWithValue(error.response?.data?.error?.message || 'Failed to fetch stats')
    }
  }
)

export const fetchMyPlugins = createAsyncThunk(
  'plugins/fetchMyPlugins',
  async (_, { rejectWithValue }) => {
    try {
      const response = await pluginService.getMyPlugins()
      return response.data
    } catch (error: any) {
      return rejectWithValue(error.response?.data?.error?.message || 'Failed to fetch my plugins')
    }
  }
)

export const createPlugin = createAsyncThunk(
  'plugins/createPlugin',
  async (pluginData: Partial<Plugin>, { rejectWithValue }) => {
    try {
      const response = await pluginService.createPlugin(pluginData)
      return response.data
    } catch (error: any) {
      return rejectWithValue(error.response?.data?.error?.message || 'Failed to create plugin')
    }
  }
)

export const updatePlugin = createAsyncThunk(
  'plugins/updatePlugin',
  async ({ id, data }: { id: string; data: Partial<Plugin> }, { rejectWithValue }) => {
    try {
      const response = await pluginService.updatePlugin(id, data)
      return response.data
    } catch (error: any) {
      return rejectWithValue(error.response?.data?.error?.message || 'Failed to update plugin')
    }
  }
)

export const deletePlugin = createAsyncThunk(
  'plugins/deletePlugin',
  async (id: string, { rejectWithValue }) => {
    try {
      await pluginService.deletePlugin(id)
      return id
    } catch (error: any) {
      return rejectWithValue(error.response?.data?.error?.message || 'Failed to delete plugin')
    }
  }
)

export const downloadPlugin = createAsyncThunk(
  'plugins/downloadPlugin',
  async ({ pluginId, version }: { pluginId: string; version?: string }, { rejectWithValue }) => {
    try {
      const response = await pluginService.downloadPlugin(pluginId, version)
      return response.data
    } catch (error: any) {
      return rejectWithValue(error.response?.data?.error?.message || 'Failed to download plugin')
    }
  }
)

export const pluginSlice = createSlice({
  name: 'plugins',
  initialState,
  reducers: {
    clearError: (state) => {
      state.error = null
    },
    setFilters: (state, action: PayloadAction<Partial<PluginFilters>>) => {
      state.filters = { ...state.filters, ...action.payload }
    },
    clearCurrentPlugin: (state) => {
      state.currentPlugin = null
      state.pluginVersions = []
      state.pluginStats = null
    },
    resetPlugins: (state) => {
      state.plugins = []
      state.pagination = null
    },
  },
  extraReducers: (builder) => {
    // Fetch plugins
    builder
      .addCase(fetchPlugins.pending, (state) => {
        state.isLoading = true
        state.error = null
      })
      .addCase(fetchPlugins.fulfilled, (state, action) => {
        state.isLoading = false
        const response = action.payload as PluginPaginatedResponse
        state.plugins = response.plugins
        // Map API pagination to internal pagination format
        state.pagination = {
          ...response.pagination,
          hasNext: response.pagination.page < Math.ceil(response.pagination.total / response.pagination.limit),
          hasPrev: response.pagination.page > 1
        }
      })
      .addCase(fetchPlugins.rejected, (state, action) => {
        state.isLoading = false
        state.error = action.payload as string
      })

    // Fetch plugin by ID
    builder
      .addCase(fetchPluginById.pending, (state) => {
        state.isLoading = true
        state.error = null
      })
      .addCase(fetchPluginById.fulfilled, (state, action) => {
        state.isLoading = false
        if (action.payload) {
          state.currentPlugin = action.payload.plugin
        }
      })
      .addCase(fetchPluginById.rejected, (state, action) => {
        state.isLoading = false
        state.error = action.payload as string
      })

    // Fetch plugin versions
    builder
      .addCase(fetchPluginVersions.pending, (state) => {
        state.isLoadingVersions = true
      })
      .addCase(fetchPluginVersions.fulfilled, (state, action) => {
        state.isLoadingVersions = false
        if (action.payload) {
          state.pluginVersions = action.payload.versions
        }
      })
      .addCase(fetchPluginVersions.rejected, (state, action) => {
        state.isLoadingVersions = false
        state.error = action.payload as string
      })

    // Fetch plugin stats
    builder
      .addCase(fetchPluginStats.pending, (state) => {
        state.isLoadingStats = true
      })
      .addCase(fetchPluginStats.fulfilled, (state, action) => {
        state.isLoadingStats = false
        if (action.payload) {
          state.pluginStats = action.payload.stats
        }
      })
      .addCase(fetchPluginStats.rejected, (state, action) => {
        state.isLoadingStats = false
        state.error = action.payload as string
      })

    // Fetch my plugins
    builder
      .addCase(fetchMyPlugins.pending, (state) => {
        state.isLoading = true
      })
      .addCase(fetchMyPlugins.fulfilled, (state, action) => {
        state.isLoading = false
        if (action.payload) {
          state.myPlugins = action.payload.plugins
        }
      })
      .addCase(fetchMyPlugins.rejected, (state, action) => {
        state.isLoading = false
        state.error = action.payload as string
      })

    // Create plugin
    builder
      .addCase(createPlugin.pending, (state) => {
        state.isLoading = true
        state.error = null
      })
      .addCase(createPlugin.fulfilled, (state, action) => {
        state.isLoading = false
        if (action.payload) {
          state.myPlugins.unshift(action.payload.plugin)
        }
      })
      .addCase(createPlugin.rejected, (state, action) => {
        state.isLoading = false
        state.error = action.payload as string
      })

    // Update plugin
    builder
      .addCase(updatePlugin.fulfilled, (state, action) => {
        if (action.payload) {
          const updatedPlugin = action.payload.plugin
          const index = state.myPlugins.findIndex(p => p.id === updatedPlugin.id)
          if (index !== -1) {
            state.myPlugins[index] = updatedPlugin
          }
          if (state.currentPlugin?.id === updatedPlugin.id) {
            state.currentPlugin = updatedPlugin
          }
        }
      })

    // Delete plugin
    builder
      .addCase(deletePlugin.fulfilled, (state, action) => {
        const deletedId = action.payload
        state.myPlugins = state.myPlugins.filter(p => p.id !== deletedId)
        if (state.currentPlugin?.id === deletedId) {
          state.currentPlugin = null
        }
      })
  },
})

export const { clearError, setFilters, clearCurrentPlugin, resetPlugins } = pluginSlice.actions

// Selectors
export const selectPlugins = (state: { plugins: PluginState }) => state.plugins.plugins
export const selectCurrentPlugin = (state: { plugins: PluginState }) => state.plugins.currentPlugin
export const selectPluginVersions = (state: { plugins: PluginState }) => state.plugins.pluginVersions
export const selectPluginStats = (state: { plugins: PluginState }) => state.plugins.pluginStats
export const selectMyPlugins = (state: { plugins: PluginState }) => state.plugins.myPlugins
export const selectPluginsLoading = (state: { plugins: PluginState }) => state.plugins.isLoading
export const selectPluginsError = (state: { plugins: PluginState }) => state.plugins.error
export const selectPluginsPagination = (state: { plugins: PluginState }) => state.plugins.pagination
export const selectPluginsFilters = (state: { plugins: PluginState }) => state.plugins.filters
